import time
import random
from decimal import Decimal

from django.db import transaction
from django.db.models import F
from rest_framework import serializers
from rest_framework.fields import SerializerMethodField
from rest_framework.serializers import ModelSerializer

from shopping.models import Classification, Commodity, CommodityImg, ShoppingCart, Order, OrderGoods, Payment
from users.models import Address


class ClassificationSerializer(ModelSerializer):
    class Meta:
        model = Classification
        fields = "__all__"


# 一级分类的序列化器
class ParentClassificationSerializer(ModelSerializer):
    # 添加一个子级分类的字段
    classification_set = ClassificationSerializer(many=True, read_only=True)

    class Meta:
        model = Classification
        fields = ['id', 'name', 'classification_set']


# 商品图片序列化器
class CommodityImgSerializer(ModelSerializer):
    class Meta:
        model = CommodityImg
        fields = ["src"]


class CommoditySerializer(ModelSerializer):
    # 商品分类字段
    classification1_name = serializers.CharField(source="classification1.name", read_only=True)
    classification2_name = serializers.CharField(source="classification2.name", read_only=True)

    # 商品图片字段
    commodityimg_set = CommodityImgSerializer(many=True, read_only=True)

    class Meta:
        model = Commodity
        exclude = ['is_delete']

        extra_kwargs = {
            "sales": {"read_only": True},
            "comments": {"read_only": True}
        }


# 购物车序列化器 - 用于处理购物车相关的数据序列化和验证
class ShoppingCartSerializer(ModelSerializer):
    # 显示购物车商品详情信息的自定义字段
    commodityDetail = SerializerMethodField()

    def get_commodityDetail(self, shoppingcart):
        """
        获取购物车中商品的详细信息

        :param shoppingcart: ShoppingCart实例对象
        :return: 商品的序列化数据
        """
        return CommoditySerializer(Commodity.objects.get(id=shoppingcart.commodity.id)).data

    class Meta:
        model = ShoppingCart
        fields = "__all__"  # 包含模型的所有字段

    def validate(self, attrs):
        """
        购物车数据验证方法 - 验证购物车商品数量和库存

        :param attrs: 验证前的数据属性字典
        :return: 验证后的数据属性字典
        """
        # 获取当前请求的用户对象
        user = self.context["request"].user

        # 验证当前登录用户与购物车用户是否一致，防止非法操作
        if user.id != attrs["user"].id:
            raise serializers.ValidationError("请勿非法操作")

        # 验证商品数量不能小于等于0
        if attrs["number"] <= 0:
            raise serializers.ValidationError("商品数量不能小于1")

        # 验证购买的商品数量不能超过商品库存
        commodity_stock = Commodity.objects.get(id=attrs["commodity"].id).stock
        if attrs["number"] > commodity_stock:
            raise serializers.ValidationError("商品库存不足")

        return attrs


# 订单序列化器 - 用于处理订单创建和相关数据序列化
class OrderSerializer(ModelSerializer):
    # 客户端传入要结算的购物车商品ID列表（仅用于写入，不在序列化结果中返回）
    cart = serializers.ListField(write_only=True)

    def create(self, validated_data):
        """
        重写订单创建方法
        客户端会传递要结算的购物车商品ID、支付方式、收货地址ID

        :param validated_data: 经过验证的用户输入数据
        :return: 创建的订单对象
        """
        # 获取当前请求的用户对象
        user = self.context["request"].user
        user_id = user.id

        # 生成唯一订单编号：时间戳+格式化6位用户ID+2位随机数
        timestamp = str(int(round(time.time() * 1000)))  # 毫秒级时间戳
        formatted_user_id = str(user_id).zfill(6)  # 格式化为6位用户ID（不足补0）
        random_num = str(random.randint(0, 99)).zfill(2)  # 2位随机数（不足补0）
        order_id = timestamp + formatted_user_id + random_num

        # 获取客户端传入的支付方式
        pay_method = validated_data.get("pay_method")

        # 获取客户端传入的收货地址ID
        try:
            # 通过客户端传递过来的ID获取收货地址信息
            address = Address.objects.get(id=validated_data.get("address"), user=user)
        except Address.DoesNotExist:
            raise serializers.ValidationError("收货地址不存在或不属于当前用户")

        # 拼接完整的收货地址信息
        address_s = f"{address.province.name} {address.city.name} {address.district.name} {address.place} 【{address.receiver}】收 Tel:{address.mobile}"

        # 使用数据库事务确保订单创建的原子性
        with transaction.atomic():
            # 创建事务保存点，用于出错时回滚
            save_point = transaction.savepoint()
            try:
                # 初始化订单信息
                order = Order.objects.create(
                    order_id=order_id,  # 订单编号
                    total_count=0,  # 初始商品总数为0
                    total_amount=Decimal('0.00'),  # 初始总金额为0（使用高精度类型）
                    pay_method=pay_method,  # 支付方式
                    # 根据支付方式设置订单状态：0:支付宝待支付 1:微信待支付 2:货到付款待发货
                    status=0 if pay_method == 0 else 1 if pay_method == 1 else 2,
                    address=address_s,  # 完整收货地址
                    user=user  # 关联用户
                )

                # 处理购物车中的商品，添加到订单中
                cart_ids = validated_data.get("cart")  # 获取要结算的购物车ID列表

                # 查询要结算的购物车商品（增加用户过滤提高安全性）
                carts = ShoppingCart.objects.filter(id__in=cart_ids, user=user)

                # 检查购物车是否为空
                if not carts.exists():
                    raise serializers.ValidationError("购物车为空或商品不存在")

                # 遍历购物车中的每个商品
                for cart in carts:
                    # 获取购物车中的商品对象
                    commodity = cart.commodity

                    # 记录商品当前的库存和销量（用于后续并发控制）
                    old_stock = commodity.stock
                    old_sales = commodity.sales

                    # 检查购买数量是否超过商品库存
                    if cart.number > commodity.stock:
                        raise serializers.ValidationError(f"商品 {commodity.name} 库存不足")

                    # 使用原子操作更新商品库存和销量（防止并发问题）
                    # filter确保只有在库存未被其他请求修改时才更新
                    res = Commodity.objects.filter(id=commodity.id, stock=old_stock).update(
                        stock=old_stock - cart.number,  # 减少库存
                        sales=old_sales + cart.number  # 增加销量
                    )

                    # 如果更新失败（说明库存已被其他请求修改），抛出异常
                    if not res:
                        raise serializers.ValidationError(f"商品 {commodity.name} 库存已变更，请重新下单")

                    # 创建订单商品详情记录
                    OrderGoods.objects.create(
                        number=cart.number,  # 商品数量
                        price=commodity.price,  # 商品单价
                        order=order,  # 关联订单
                        commodity=commodity  # 关联商品
                    )

                    # 累加订单总商品数量和总金额
                    order.total_count += cart.number
                    order.total_amount += cart.number * commodity.price

                # 保存订单最终的总数量和总金额
                order.save()

                # 删除购物车中已结算的商品
                carts.delete()

            except Exception as e:
                # 发生异常时回滚到保存点
                transaction.savepoint_rollback(save_point)
                # 如果是已知的验证错误则直接抛出，否则包装成验证错误
                if isinstance(e, serializers.ValidationError):
                    raise e
                else:
                    raise serializers.ValidationError("订单创建失败")
            else:
                # 操作成功时提交事务
                transaction.savepoint_commit(save_point)

        return order

    class Meta:
        model = Order
        fields = "__all__"  # 包含模型的所有字段

        # 设置只读字段，这些字段由系统自动填充，不接受客户端输入
        read_only_fields = ["order_id", "total_count", "total_amount", "status", "user"]


# 支付序列化器
class PaymentSerializer(ModelSerializer):
    class Meta:
        model = Payment
        fields = "__all__"
